﻿//============================================================================
// BDInfo - Blu-ray Video and Audio Analysis Tool
// Copyright © 2009 Cinema Squid
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//=============================================================================

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using System.Net;
using System.Globalization;
using System.Diagnostics;


namespace BD2MKV
{    
    public partial class FormMain : Form
    {
        private BDROM BDROM = null;
        private Muxer myMuxer = null;
        private int CustomPlaylistCount = 0;

        private string seriesId = null;
        private string language = null;
        private string seriesName = null;
       
        private string ftpServer = null;
        private string ftpUserName = null;
        private string ftpPWD = null;
        private string ftpDir = null;

        private int lastQueueItem = 0;
        bool []combos = new bool[4];

        private List<BackgroundWorker> muxWorker = new List<BackgroundWorker>();
        static readonly object padlock = new object();

        DateTime []timeStarted = new DateTime[4];                

        public List<Muxer> muxQueue = new List<Muxer>();

        #region UI Handlers

        private ListViewColumnSorter PlaylistColumnSorter;

        public static string RemoveInvalidFileNameChars(string fileName)
        {
            char[] invalidFileChars = Path.GetInvalidFileNameChars();

            foreach (char invalidFChar in invalidFileChars)
            {
                fileName = fileName.Replace(invalidFChar.ToString(), "");
            }
            return fileName;

        }

        private void UpdateCheckbox(int index, string label)
        {
            switch (index)
            {
                case 0:
                    checkBoxThread1.Invoke(new MethodInvoker(delegate() { checkBoxThread1.Text = label; }));
                    break;
                case 1:
                    checkBoxThread2.Invoke(new MethodInvoker(delegate() { checkBoxThread2.Text = label; }));
                    break;
                case 2:
                    checkBoxThread3.Invoke(new MethodInvoker(delegate() { checkBoxThread3.Text = label; }));
                    break;
                case 3:
                    checkBoxThread4.Invoke(new MethodInvoker(delegate() { checkBoxThread4.Text = label; }));
                    break;
            }
        }

        private void UpdateProgressBar(int index, int progress, string label)
        {
            if ((progress != 0)  && (label != ""))
                label += " - ";

            switch (index)
            {
                case 0:
                    progressBarThread1.Invoke(new MethodInvoker(delegate() 
                        {
                            progressBarThread1.Label = label;
                            progressBarThread1.Value = progress;
                        }));
                    break;
                case 1:
                    progressBarThread2.Invoke(new MethodInvoker(delegate() 
                        {
                            progressBarThread2.Label = label;
                            progressBarThread2.Value = progress;
                        }));       
                    break;
                case 2:
                    progressBarThread3.Invoke(new MethodInvoker(delegate() 
                        {
                            progressBarThread3.Label = label;
                            progressBarThread3.Value = progress;
                        }));
                    break;
                case 3:
                    progressBarThread4.Invoke(new MethodInvoker(delegate() 
                        {
                            progressBarThread4.Label = label;
                            progressBarThread4.Value = progress;
                        }));
                    break;
            }
        }

        private void UpdateText(int index, string line, int type)
        {
            Color color = new Color();
            
            switch (type) 
            {
                case 2: 
                    color = Color.Red;
                    break;
                case 3:
                    color = Color.Black;
                    break;
                default:
                    color = Color.Blue;
                    break;
            }
            line += "\n";
            switch (index)
            {
                case 0:
                    richTextBoxThread1.Invoke(new MethodInvoker(delegate() 
                    { 
                        richTextBoxThread1.ForeColor = color; 
                        richTextBoxThread1.AppendText(line);
                    }));
                    break;
                case 1:
                    richTextBoxThread2.Invoke(new MethodInvoker(delegate() { richTextBoxThread2.ForeColor = color; richTextBoxThread2.AppendText(line); }));
                    break;
                case 2:
                    richTextBoxThread3.Invoke(new MethodInvoker(delegate() { richTextBoxThread3.ForeColor = color; richTextBoxThread3.AppendText(line); }));
                    break;
                case 3:
                    richTextBoxThread4.Invoke(new MethodInvoker(delegate() { richTextBoxThread4.ForeColor = color; richTextBoxThread4.AppendText(line); }));
                    break;
            }
        }

        private void muxQueueProgress(object sender, ProgressChangedEventArgs e)
        {

            ReportMessage msg = (ReportMessage)e.UserState;
            int index = msg.thread;
            

            TimeSpan elapsedTime = DateTime.Now - timeStarted[index];
            TimeSpan remainingTime;

            if (e.ProgressPercentage > 0)
            {
                double progress = (double)e.ProgressPercentage / (double)1000;

                if (progress > 0 && progress < 1)
                {
                    remainingTime = new TimeSpan(
                        (long)((double)elapsedTime.Ticks / progress) - elapsedTime.Ticks);
                }
                else
                {
                    remainingTime = new TimeSpan(0);
                }

                UpdateCheckbox(index, "Worker " + index.ToString() + " - Time Remaining / Elapsed:  " +
                    string.Format("{0:D2}:{1:D2}:{2:D2}", remainingTime.Hours, remainingTime.Minutes, remainingTime.Seconds) + " / " +
                    string.Format("{0:D2}:{1:D2}:{2:D2}", elapsedTime.Hours, elapsedTime.Minutes, elapsedTime.Seconds) 
                    );
                string label = msg.line.Replace("###---###", "");
                UpdateProgressBar(index, e.ProgressPercentage, label);
            } 

            if (!(msg.line.StartsWith("###---###"))) 
                UpdateText(index, msg.line, msg.type);
        }

        private void muxQueueWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                int index = (int)e.Argument;             
                
                while (true) 
                {
                    Thread.Sleep(1);
                    if (!combos[index]) continue;

                    foreach (Muxer m in muxQueue)
                    {
                        if (m.jobStatus == 1)
                        {
                            lock (padlock)
                            {
                                if (m.jobStatus == 1)
                                {
                                    m.jobStatus = 3;
                                }
                            }
                            timeStarted[index] = DateTime.Now;
                          
                            listViewQueue.Invoke(new MethodInvoker(delegate() 
                            {   ListViewItem iList = listViewQueue.FindItemWithText(m.jobId.ToString(), false, 0);
                                listViewQueue.Items[iList.Index].SubItems[2].Text = "In Progress..."; 
                            }));                            
                            
                            m.worker = muxWorker[index];
                            m.thread = index;
                            switch (m.jobType)
                            {
                                case 1:
                                    m.DeMux();
                                    break;
                                case 2:
                                    m.Subtitles();
                                    break;
                                case 3:
                                    m.Mux();
                                    break;
                                case 4:
                                    m.RemoveTemps();
                                    break;
                                case 5:
                                    m.FTP();
                                    break;
                                case 6:
                                    m.Encode();
                                    break;
                            }
                        
                            m.jobStatus = 4;
                            listViewQueue.Invoke(new MethodInvoker(delegate()
                            {
                                ListViewItem iList = listViewQueue.FindItemWithText(m.jobId.ToString(), false, 0);
                                listViewQueue.Items[iList.Index].SubItems[2].Text = "Finished"; 
                            }));

                            foreach (Muxer m1 in muxQueue)
                                if ((m1.dependsOn == m.jobId) && ((m1.jobStatus == 2) || (m1.jobStatus == 12)))
                                {
                                    int js = 1;
                                    string lbl = "Ready";

                                    if (m1.jobStatus == 12)
                                    {
                                        js = 11;
                                        lbl = "Ready (On hold)";
                                    }

                                    listViewQueue.Invoke(new MethodInvoker(delegate()
                                    {
                                        ListViewItem iList = listViewQueue.FindItemWithText(m1.jobId.ToString(), false, 0);
                                        listViewQueue.Items[iList.Index].SubItems[2].Text = lbl;
                                    }));
                                    
                                    m1.jobStatus = js;
                                }
                            UpdateCheckbox(index, "Worker " + index.ToString());
                            UpdateProgressBar(index, 0, "");
                            UpdateText(index, "*****************************", 3);
                            UpdateText(index, "Idle...", 3);
                            break;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                e.Result = ex;
            }
        }

        private void muxQueueCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Result != null)
            {
                string msg = string.Format(
                    "{0}", ((Exception)e.Result).Message);
                MessageBox.Show(msg, "BDMux Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
        }

        public FormMain()
        {
            InitializeComponent();

            combos[0] = false;
            combos[1] = false;
            combos[2] = false;
            combos[3] = false;

            PlaylistColumnSorter = new ListViewColumnSorter();
            listViewPlaylistFiles.ListViewItemSorter = PlaylistColumnSorter;
            textBoxTemp.Text = System.IO.Path.GetTempPath();
            
            
            int workers = 4;

            for (int i = 0; i < workers; i++)
            {
                BackgroundWorker worker = new BackgroundWorker();
                worker.WorkerReportsProgress = true;
                worker.WorkerSupportsCancellation = true;
                worker.DoWork += muxQueueWork;
                worker.ProgressChanged += muxQueueProgress;
                worker.RunWorkerCompleted += muxQueueCompleted;
                muxWorker.Add(worker);
            }
            int j = 0;
            foreach (BackgroundWorker bg in muxWorker)
            {
                bg.RunWorkerAsync(j);
                j++;
            }

        }

        private void FormMain_Load(object sender, EventArgs e)
        {
            ResetColumnWidths();
            textBoxSource.Text = BDMuxSettings.LastFilePath;
            textBoxTarget.Text = BDMuxSettings.LastTarget;
            checkBoxFTP.Checked = BDMuxSettings.FTPTargets;
            buttonFTP.Enabled = BDMuxSettings.FTPTargets;
            checkBoxRemove.Checked = BDMuxSettings.RemoveTemp;
            comboBoxScheme.SelectedIndex = BDMuxSettings.Schema;
            comboBoxTarget.SelectedIndex = 0;
            comboBoxX264conv.SelectedIndex = 0;
            comboBoxSource.SelectedIndex = 0;
            ftpDir = BDMuxSettings.FTPDir;
            ftpServer = BDMuxSettings.FTPServer;
            ftpUserName = BDMuxSettings.FTPUser;
            ftpPWD = BDMuxSettings.FTPPWD;
        }

        private void textBoxSource_TextChanged(object sender, EventArgs e)
        {
            if (textBoxSource.Text.Length > 0)
            {
                buttonRescan.Enabled = true;
            }
            else
            {
                buttonRescan.Enabled = false;
            }
        }

        private void buttonBrowse_Click(
            object sender,
            EventArgs e)
        {
            string path = null;
            try
            {
                if (comboBoxSource.SelectedIndex == 0) 
                {
                    FolderBrowserDialog dialog = new FolderBrowserDialog();
                    dialog.Description = "Select a Blu-ray BDMV Folder:";
                    dialog.ShowNewFolderButton = false;
                    if (dialog.ShowDialog() == DialogResult.OK)
                    {
                        path = dialog.SelectedPath;
                        textBoxSource.Text = path;
                        InitBDROM(path);
                    }
                } else
                {
                    OpenFileDialog dialogFile = new OpenFileDialog();
                    dialogFile.Title = "Select a Media File:";
                    dialogFile.CheckFileExists = true;
                    dialogFile.Filter = "Media Files (*.mkv)|*.MKV";
                    dialogFile.Multiselect = false;                    
                    if (dialogFile.ShowDialog() == DialogResult.OK)
                    {
                        path = dialogFile.FileName;
                        textBoxSource.Text = path;
                        InitFile(path);
                    }
                }
                
            }
            catch (Exception ex)
            {
                string msg = string.Format(
                    "Error opening path {0}: {1}{2}",
                    path,
                    ex.Message,
                    Environment.NewLine);

                MessageBox.Show(msg, "BDMux Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void buttonRescan_Click(object sender, EventArgs e)
        {
            string path = textBoxSource.Text;
            try
            {
                InitBDROM(path);
            }
            catch (Exception ex)
            {
                string msg = string.Format(
                    "Error opening path {0}: {1}{2}",
                    path,
                    ex.Message,
                    Environment.NewLine);

                MessageBox.Show(msg, "BDInfo Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void buttonSettings_Click(
            object sender,
            EventArgs e)
        {
            FormSettings settings = new FormSettings();
            settings.ShowDialog();
        }

        private void buttonSelectAll_Click(object sender, EventArgs e)
        {
            foreach (ListViewItem item in listViewPlaylistFiles.Items)
            {
                item.Checked = true;
            }
        }

        private void buttonUnselectAll_Click(object sender, EventArgs e)
        {
            foreach (ListViewItem item in listViewPlaylistFiles.Items)
            {
                item.Checked = false;
            }
        }

        private void buttonCustomPlaylist_Click(
            object sender,
            EventArgs e)
        {
            string name = string.Format(
                "USER.{0}", (++CustomPlaylistCount).ToString("D3"));

            FormPlaylist form = new FormPlaylist(name, BDROM, OnCustomPlaylistAdded);
            form.LoadPlaylists();
            form.Show();
        }

        public void OnCustomPlaylistAdded()
        {
            LoadPlaylists();
        }

        private void buttonScan_Click(
            object sender,
            EventArgs e)
        {
            ScanBDROM();
        }

        private void buttonViewReport_Click(
            object sender,
            EventArgs e)
        {
            GenerateReport();
        }
        private void listViewPlaylistFiles_SelectedIndexChanged(
            object sender,
            EventArgs e)
        {
            LoadPlaylist();
            if (listViewPlaylistFiles.SelectedItems.Count > 0)
            {
                LoadSeries();
                buttonRemove.Enabled = true;
                buttonRename.Enabled = true;
                textBoxRename.Enabled = true;
                textBoxRename.Text = listViewPlaylistFiles.SelectedItems[0].SubItems[5].Text;
            }
            else
            {
                buttonRemove.Enabled = false;
                buttonRename.Enabled = false;
                textBoxRename.Enabled = false; 
            }

        }

        private void listViewPlaylistFiles_ColumnClick(
            object sender,
            ColumnClickEventArgs e)
        {
            if (e.Column == PlaylistColumnSorter.SortColumn)
            {
                if (PlaylistColumnSorter.Order == SortOrder.Ascending)
                {
                    PlaylistColumnSorter.Order = SortOrder.Descending;
                }
                else
                {
                    PlaylistColumnSorter.Order = SortOrder.Ascending;
                }
            }
            else
            {
                PlaylistColumnSorter.SortColumn = e.Column;
                PlaylistColumnSorter.Order = SortOrder.Ascending;
            }
            listViewPlaylistFiles.Sort();
        }

        private void ResetColumnWidths()
        {
            listViewPlaylistFiles.Columns[0].Width =
                (int)(listViewPlaylistFiles.ClientSize.Width * 0.22);
            listViewPlaylistFiles.Columns[1].Width =
                (int)(listViewPlaylistFiles.ClientSize.Width * 0.08);
            listViewPlaylistFiles.Columns[2].Width =
                (int)(listViewPlaylistFiles.ClientSize.Width * 0.10);
            listViewPlaylistFiles.Columns[3].Width =
                (int)(listViewPlaylistFiles.ClientSize.Width * 0.15);
            listViewPlaylistFiles.Columns[4].Width =
                (int)(listViewPlaylistFiles.ClientSize.Width * 0.15);
            listViewPlaylistFiles.Columns[5].Width =
                (int)(listViewPlaylistFiles.ClientSize.Width * 0.30);

            listViewStreamFiles.Columns[0].Width =
                (int)(listViewStreamFiles.ClientSize.Width * 0.23);
            listViewStreamFiles.Columns[1].Width =
                (int)(listViewStreamFiles.ClientSize.Width * 0.08);
            listViewStreamFiles.Columns[2].Width =
                (int)(listViewStreamFiles.ClientSize.Width * 0.23);
            listViewStreamFiles.Columns[3].Width =
                (int)(listViewStreamFiles.ClientSize.Width * 0.23);
            listViewStreamFiles.Columns[4].Width =
                (int)(listViewStreamFiles.ClientSize.Width * 0.23);

            listViewStreams.Columns[0].Width =
                (int)(listViewStreams.ClientSize.Width * 0.25);
            listViewStreams.Columns[1].Width =
                (int)(listViewStreams.ClientSize.Width * 0.15);
            listViewStreams.Columns[2].Width =
                (int)(listViewStreams.ClientSize.Width * 0.15);
            listViewStreams.Columns[3].Width =
                (int)(listViewStreams.ClientSize.Width * 0.45);

            listViewQueue.Columns[0].Width =
                (int)(listViewQueue.ClientSize.Width * 0.20);
            listViewQueue.Columns[1].Width =
                (int)(listViewQueue.ClientSize.Width * 0.50);
            listViewQueue.Columns[2].Width =
                (int)(listViewQueue.ClientSize.Width * 0.30);
        }

        private void FormMain_FormClosing(
            object sender,
            FormClosingEventArgs e)
        {
            if (comboBoxSource.SelectedIndex == 0)
                BDMuxSettings.LastPath = textBoxSource.Text;
            else
                BDMuxSettings.LastFilePath = textBoxSource.Text;

            BDMuxSettings.LastTarget = textBoxTarget.Text;
            BDMuxSettings.FTPTargets = checkBoxFTP.Checked;
            BDMuxSettings.RemoveTemp = checkBoxRemove.Checked;
            BDMuxSettings.Schema = comboBoxScheme.SelectedIndex;
            BDMuxSettings.SaveSettings();

            if (InitBDROMWorker != null &&
                InitBDROMWorker.IsBusy)
            {
                InitBDROMWorker.CancelAsync();
            }
            if (ScanBDROMWorker != null &&
                ScanBDROMWorker.IsBusy)
            {
                ScanBDROMWorker.CancelAsync();
            }
            if (ReportWorker != null &&
                ReportWorker.IsBusy)
            {
                ReportWorker.CancelAsync();
            }
        }

        #endregion

        #region BDROM Initialization Worker

        private BackgroundWorker InitBDROMWorker = null;

        private void InitBDROM(
            string path)
        {
            ShowNotification("Please wait while we scan the disc...");

            CustomPlaylistCount = 0;
            tabControl1.Enabled = false;
            /* buttonBrowse.Enabled = false;
            buttonRescan.Enabled = false;
            buttonShow.Enabled = false;
            buttonSelectAll.Enabled = false;
            buttonUnselectAll.Enabled = false;
            buttonCustomPlaylist.Enabled = false;
            buttonScan.Enabled = false;
            buttonMux.Enabled = false;
            buttonViewReport.Enabled = false;
            textBoxDetails.Enabled = false;     
            listViewPlaylistFiles.Enabled = false;
            listViewStreamFiles.Enabled = false;
            listViewStreams.Enabled = false;
            textBoxDetails.Clear();
            listViewPlaylistFiles.Items.Clear();
            listViewStreamFiles.Items.Clear();
            listViewStreams.Items.Clear(); */

            InitBDROMWorker = new BackgroundWorker();
            InitBDROMWorker.WorkerReportsProgress = true;
            InitBDROMWorker.WorkerSupportsCancellation = true;
            InitBDROMWorker.DoWork += InitBDROMWork;
            InitBDROMWorker.ProgressChanged += InitBDROMProgress;
            InitBDROMWorker.RunWorkerCompleted += InitBDROMCompleted;
            InitBDROMWorker.RunWorkerAsync(path);
        }

        private void InitBDROMWork(
            object sender,
            DoWorkEventArgs e)
        {
            try
            {
                BDROM = new BDROM((string)e.Argument);
                BDROM.StreamClipFileScanError += new BDROM.OnStreamClipFileScanError(BDROM_StreamClipFileScanError);
                BDROM.StreamFileScanError += new BDROM.OnStreamFileScanError(BDROM_StreamFileScanError);
                BDROM.PlaylistFileScanError += new BDROM.OnPlaylistFileScanError(BDROM_PlaylistFileScanError);
                BDROM.Scan();
                e.Result = null;
            }
            catch (Exception ex)
            {
                e.Result = ex;
            }
        }

        protected bool BDROM_PlaylistFileScanError(TSPlaylistFile playlistFile, Exception ex)
        {
            DialogResult result = MessageBox.Show(string.Format(
                "An error occurred while scanning the playlist file {0}.\n\nThe disc may be copy-protected or damaged.\n\nDo you want to continue scanning the playlist files?", playlistFile.Name),
                "BDInfo Scan Error", MessageBoxButtons.YesNo);

            if (result == DialogResult.Yes) return true;
            else return false;
        }

        protected bool BDROM_StreamFileScanError(TSStreamFile streamFile, Exception ex)
        {
            DialogResult result = MessageBox.Show(string.Format(
                "An error occurred while scanning the stream file {0}.\n\nThe disc may be copy-protected or damaged.\n\nDo you want to continue scanning the stream files?", streamFile.Name),
                "BDInfo Scan Error", MessageBoxButtons.YesNo);

            if (result == DialogResult.Yes) return true;
            else return false;
        }

        protected bool BDROM_StreamClipFileScanError(TSStreamClipFile streamClipFile, Exception ex)
        {
            DialogResult result = MessageBox.Show(string.Format(
                "An error occurred while scanning the stream clip file {0}.\n\nThe disc may be copy-protected or damaged.\n\nDo you want to continue scanning the stream clip files?", streamClipFile.Name),
                "BDInfo Scan Error", MessageBoxButtons.YesNo);

            if (result == DialogResult.Yes) return true;
            else return false;
        }

        private void InitBDROMProgress(
            object sender,
            ProgressChangedEventArgs e)
        {
        }

        private void InitBDROMCompleted(
            object sender,
            RunWorkerCompletedEventArgs e)
        {
            HideNotification();

            if (e.Result != null)
            {
                string msg = string.Format(
                    "{0}", ((Exception)e.Result).Message);
                MessageBox.Show(msg, "BDMux Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                //buttonBrowse.Enabled = true;
                //buttonRescan.Enabled = true;
                tabControl1.Enabled = true; 
                return;
            }

            /* buttonBrowse.Enabled = true;
            buttonRescan.Enabled = true;
            buttonScan.Enabled = true;
            buttonShow.Enabled = true;
            buttonSelectAll.Enabled = true;
            buttonUnselectAll.Enabled = true;
            buttonCustomPlaylist.Enabled = true;
            buttonViewReport.Enabled = true;
            textBoxDetails.Enabled = true;
            listViewPlaylistFiles.Enabled = true;
            listViewStreamFiles.Enabled = true;
            listViewStreams.Enabled = true;
             */
            tabControl1.Enabled = true;
            groupBoxMovie.Enabled = true;
            radioButtonMovie.Enabled = true;
            radioButtonTV.Enabled = true;
            buttonSelectAll.Enabled = true;
            buttonUnselectAll.Enabled = true;
            buttonCustomPlaylist.Enabled = true;
            listViewPlaylistFiles.Enabled = true;
            listViewStreams.Enabled = true;

            if (comboBoxSource.SelectedIndex == 0)
            {
                listViewStreamFiles.Enabled = true;
                buttonScan.Enabled = true;
                buttonViewReport.Enabled = true;
            }
            else
            {
                listViewStreamFiles.Enabled = false;
                buttonScan.Enabled = false;
                buttonViewReport.Enabled = false;
            }


            progressBarScan.Value = 0;
            labelProgress.Text = "";
            labelTimeElapsed.Text = "00:00:00";
            labelTimeRemaining.Text = "00:00:00";

            textBoxDetails.Text += string.Format(
                "Detected BDMV Folder: {0} ({1}) {2}",
                BDROM.DirectoryBDMV.FullName,
                BDROM.VolumeLabel,
                Environment.NewLine);

            if (BDROM.IsBDPlus)
            {
                textBoxDetails.Text += "BD+ detected. ";
            }
            if (BDROM.IsBDJava)
            {
                textBoxDetails.Text += "BD-Java detected. ";
            }
            if (BDROM.IsDBOX)
            {
                textBoxDetails.Text += "D-BOX Motion Code detected. ";
            }
            if (BDROM.IsBDPlus || BDROM.IsBDJava || BDROM.IsDBOX)
            {
                textBoxDetails.Text += Environment.NewLine;
            }

            textBoxDetails.Text += string.Format(
                "Disc Size: {0:N0} bytes{1}",
                BDROM.Size,
                Environment.NewLine);

            string lab = BDROM.VolumeLabel.Replace('_', ' ');

            if (lab.Length > 5)
                if (lab.Substring(lab.Length - 5, 4) == "DISC")
                {
                    lab = lab.Remove(lab.Length - 6);
                }
            textBoxSeries.Text = lab;
            textBoxMovie.Text = lab;
            LoadPlaylists();
        }

        #endregion

        #region File/Stream Lists

        private void LoadPlaylists()
        {
            listViewPlaylistFiles.Items.Clear();
            listViewStreamFiles.Items.Clear();
            listViewStreams.Items.Clear();

            if (BDROM == null) return;

            bool hasHiddenTracks = false;

          List<List<TSPlaylistFile>> groups = new List<List<TSPlaylistFile>>();

            TSPlaylistFile[] sortedPlaylistFiles = new TSPlaylistFile[BDROM.PlaylistFiles.Count];
            BDROM.PlaylistFiles.Values.CopyTo(sortedPlaylistFiles, 0);
            Array.Sort(sortedPlaylistFiles, ComparePlaylistFiles);

            foreach (TSPlaylistFile playlist1
                in sortedPlaylistFiles)
            {
                if (!playlist1.IsValid) continue;

                int matchingGroupIndex = 0;
                for (int groupIndex = 0; groupIndex < groups.Count; groupIndex++)
                {
                    List<TSPlaylistFile> group = groups[groupIndex];
                    foreach (TSPlaylistFile playlist2 in group)
                    {
                        if (!playlist2.IsValid) continue;

                        foreach (TSStreamClip clip1 in playlist1.StreamClips)
                        {
                            foreach (TSStreamClip clip2 in playlist2.StreamClips)
                            {
                                if (clip1.Name == clip2.Name)
                                {
                                    matchingGroupIndex = groupIndex + 1;
                                    break;
                                }
                            }
                            if (matchingGroupIndex > 0) break;
                        }
                        if (matchingGroupIndex > 0) break;
                    }
                    if (matchingGroupIndex > 0) break;
                }
                if (matchingGroupIndex > 0)
                {
                    groups[matchingGroupIndex - 1].Add(playlist1);
                }
                else
                {
                    groups.Add(new List<TSPlaylistFile> { playlist1 });
                    //matchingGroupIndex = groups.Count;
                }
                //playlistGroup[playlist1.Name] = matchingGroupIndex;
            }

            int i = 1;
            for (int groupIndex = 0; groupIndex < groups.Count; groupIndex++)
            {
                List<TSPlaylistFile> group = groups[groupIndex];
                group.Sort(ComparePlaylistFiles);

                foreach (TSPlaylistFile playlist in group)
                //in BDROM.PlaylistFiles.Values)
                {
                    if (!playlist.IsValid) continue;

                    if (playlist.HasHiddenTracks)
                    {
                        hasHiddenTracks = true;
                    }

                    ListViewItem.ListViewSubItem playlistIndex =
                        new ListViewItem.ListViewSubItem();
                    playlistIndex.Text = (groupIndex + 1).ToString();
                    playlistIndex.Tag = groupIndex;

                    ListViewItem.ListViewSubItem playlistName =
                        new ListViewItem.ListViewSubItem();
                    playlistName.Text = playlist.Name;
                    playlistName.Tag = i.ToString();
                    i++;

                    TimeSpan playlistLengthSpan =
                        new TimeSpan((long)(playlist.TotalLength * 10000000));
                    ListViewItem.ListViewSubItem playlistLength =
                        new ListViewItem.ListViewSubItem();
                    playlistLength.Text = string.Format(
                        "{0:D2}:{1:D2}:{2:D2}",
                        playlistLengthSpan.Hours,
                        playlistLengthSpan.Minutes,
                        playlistLengthSpan.Seconds);
                    playlistLength.Tag = playlist.TotalLength;

                    ListViewItem.ListViewSubItem playlistSize =
                        new ListViewItem.ListViewSubItem();
                    if (playlist.FileSize > 0)
                    {
                        playlistSize.Text = playlist.FileSize.ToString("N0");
                    }
                    else
                    {
                        playlistSize.Text = "-";
                    }
                    playlistSize.Tag = playlist.FileSize;

                    ListViewItem.ListViewSubItem playlistSize2 =
                        new ListViewItem.ListViewSubItem();
                    if (playlist.TotalAngleSize > 0)
                    {
                        playlistSize2.Text = (playlist.TotalAngleSize).ToString("N0");
                    }
                    else
                    {
                        playlistSize2.Text = "-";
                    }
                    playlistSize2.Tag = playlist.TotalAngleSize;

                    ListViewItem.ListViewSubItem playlistFinalName =
                        new ListViewItem.ListViewSubItem();
                    playlistFinalName.Text = "";

                    ListViewItem.ListViewSubItem[] playlistSubItems =
                        new ListViewItem.ListViewSubItem[]
                        {
                            playlistName,
                            playlistIndex,
                            playlistLength,
                            playlistSize,
                            playlistSize2,
                            playlistFinalName
                        };

                    ListViewItem playlistItem =
                        new ListViewItem(playlistSubItems, 0);
                    playlistItem.Checked = true;
                    listViewPlaylistFiles.Items.Add(playlistItem);
                }
            }

            if (hasHiddenTracks)
            {
                textBoxDetails.Text += "(*) Some playlists on this disc have hidden tracks. These tracks are marked with an asterisk.";
            }

            if (listViewPlaylistFiles.Items.Count > 0)
            {
                listViewPlaylistFiles.Items[0].Selected = true;
                
                if (listViewPlaylistFiles.Items.Count > 2)
                    radioButtonTV.Enabled = true;
                else
                    radioButtonMovie.Enabled = true;

                string lab = BDROM.VolumeLabel.Replace('_', ' ');
                if (lab.Length > 5)
                    if (lab.Substring(lab.Length - 5, 4) == "DISC")
                    {
                        lab = lab.Remove(lab.Length - 6);
                    }
                if (lab == "")
                    lab = "NO_LABEL";
                
                TextInfo TI = new CultureInfo("en-US", false).TextInfo;
                seriesName = TI.ToTitleCase(RemoveInvalidFileNameChars(lab));
                LoadSeries();
            }

            ResetColumnWidths();
        }

        private void LoadPlaylist()
        {
            listViewStreamFiles.Items.Clear();
            listViewStreams.Items.Clear();

            if (BDROM == null) return;
            if (listViewPlaylistFiles.SelectedItems.Count == 0) return;

            ListViewItem playlistItem = listViewPlaylistFiles.SelectedItems[0];
            if (playlistItem == null) return;

            TSPlaylistFile playlist = null;
            string playlistFileName = playlistItem.Text;
            if (BDROM.PlaylistFiles.ContainsKey(playlistFileName))
            {
                playlist = BDROM.PlaylistFiles[playlistFileName];
            }
            if (playlist == null) return;

            int clipCount = 0;
            foreach (TSStreamClip clip in playlist.StreamClips)
            {
                if (clip.AngleIndex == 0)
                {
                    ++clipCount;
                }

                ListViewItem.ListViewSubItem clipIndex =
                    new ListViewItem.ListViewSubItem();
                clipIndex.Text = clipCount.ToString();
                clipIndex.Tag = clipCount;

                ListViewItem.ListViewSubItem clipName =
                    new ListViewItem.ListViewSubItem();
                clipName.Text = clip.Name;
                clipName.Tag = clip.Name;
                if (clip.AngleIndex > 0)
                {
                    clipName.Text += string.Format(
                        " ({0})", clip.AngleIndex);
                }

                TimeSpan clipLengthSpan =
                    new TimeSpan((long)(clip.Length * 10000000));

                ListViewItem.ListViewSubItem clipLength =
                    new ListViewItem.ListViewSubItem();
                clipLength.Text = string.Format(
                    "{0:D2}:{1:D2}:{2:D2}",
                    clipLengthSpan.Hours,
                    clipLengthSpan.Minutes,
                    clipLengthSpan.Seconds);
                clipLength.Tag = clip.Length;

                ListViewItem.ListViewSubItem clipSize =
                    new ListViewItem.ListViewSubItem();
                if (clip.FileSize > 0)
                {
                    clipSize.Text = clip.FileSize.ToString("N0");
                }
                else
                {
                    clipSize.Text = "-";
                }
                clipSize.Tag = clip.FileSize;

                ListViewItem.ListViewSubItem clipSize2 =
                    new ListViewItem.ListViewSubItem();
                if (clip.PacketSize > 0)
                {
                    clipSize2.Text = clip.PacketSize.ToString("N0");
                }
                else
                {
                    clipSize2.Text = "-";
                }
                clipSize2.Tag = clip.PacketSize;

                ListViewItem.ListViewSubItem[] streamFileSubItems =
                    new ListViewItem.ListViewSubItem[]
                    {
                        clipName,
                        clipIndex,
                        clipLength,
                        clipSize,
                        clipSize2
                    };

                ListViewItem streamFileItem =
                    new ListViewItem(streamFileSubItems, 0);
                listViewStreamFiles.Items.Add(streamFileItem);
            }

            foreach (TSStream stream in playlist.SortedStreams)
            {
                ListViewItem.ListViewSubItem codec =
                    new ListViewItem.ListViewSubItem();
                codec.Text = stream.CodecName;
                if (stream.AngleIndex > 0)
                {
                    codec.Text += string.Format(
                        " ({0})", stream.AngleIndex);
                }
                codec.Tag = stream.CodecName;

                if (stream.IsHidden)
                {
                    codec.Text = "* " + codec.Text;
                }

                ListViewItem.ListViewSubItem language =
                    new ListViewItem.ListViewSubItem();
                language.Text = stream.LanguageName;
                language.Tag = stream.LanguageName;

                ListViewItem.ListViewSubItem bitrate =
                    new ListViewItem.ListViewSubItem();

                if (stream.AngleIndex > 0)
                {
                    if (stream.ActiveBitRate > 0)
                    {
                        bitrate.Text = string.Format(
                            "{0} kbps", Math.Round((double)stream.ActiveBitRate / 1000));
                    }
                    else
                    {
                        bitrate.Text = "-";
                    }
                    bitrate.Tag = stream.ActiveBitRate;
                }
                else
                {
                    if (stream.BitRate > 0)
                    {
                        bitrate.Text = string.Format(
                            "{0} kbps", Math.Round((double)stream.BitRate / 1000));
                    }
                    else
                    {
                        bitrate.Text = "-";
                    }
                    bitrate.Tag = stream.BitRate;
                }

                ListViewItem.ListViewSubItem description =
                    new ListViewItem.ListViewSubItem();
                description.Text = stream.Description;
                description.Tag = stream.Description;

                ListViewItem.ListViewSubItem[] streamSubItems =
                    new ListViewItem.ListViewSubItem[]
                    {
                        codec,
                        language,
                        bitrate,
                        description
                    };

                ListViewItem streamItem =
                    new ListViewItem(streamSubItems, 0);
                streamItem.Tag = stream.PID;
                streamItem.Checked = stream.process;
                listViewStreams.Items.Add(streamItem);
            }

            ResetColumnWidths();
        }

        private void UpdatePlaylistBitrates()
        {
            foreach (ListViewItem item in listViewPlaylistFiles.Items)
            {
                string playlistName = (string)item.SubItems[0].Tag;
                if (BDROM.PlaylistFiles.ContainsKey(playlistName))
                {
                    TSPlaylistFile playlist =
                        BDROM.PlaylistFiles[playlistName];
                    item.SubItems[4].Text = string.Format(
                        "{0}", (playlist.TotalAngleSize).ToString("N0"));
                    item.SubItems[4].Tag = playlist.TotalAngleSize;
                }
            }

            if (listViewPlaylistFiles.SelectedItems.Count == 0)
            {
                return;
            }

            ListViewItem selectedPlaylistItem =
                listViewPlaylistFiles.SelectedItems[0];
            if (selectedPlaylistItem == null)
            {
                return;
            }

            string selectedPlaylistName = (string)selectedPlaylistItem.SubItems[0].Tag;
            TSPlaylistFile selectedPlaylist = null;
            if (BDROM.PlaylistFiles.ContainsKey(selectedPlaylistName))
            {
                selectedPlaylist = BDROM.PlaylistFiles[selectedPlaylistName];
            }
            if (selectedPlaylist == null)
            {
                return;
            }

            for (int i = 0; i < listViewStreamFiles.Items.Count; i++)
            {
                ListViewItem item = listViewStreamFiles.Items[i];
                if (selectedPlaylist.StreamClips.Count > i &&
                    selectedPlaylist.StreamClips[i].Name == (string)item.SubItems[0].Tag)
                {
                    item.SubItems[4].Text = string.Format(
                         "{0}", (selectedPlaylist.StreamClips[i].PacketSize).ToString("N0"));
                    item.Tag = selectedPlaylist.StreamClips[i].PacketSize;

                }
            }

            for (int i = 0; i < listViewStreams.Items.Count; i++)
            {
                ListViewItem item = listViewStreams.Items[i];
                if (i < selectedPlaylist.SortedStreams.Count &&
                    selectedPlaylist.SortedStreams[i].PID == (ushort)item.Tag)
                {
                    TSStream stream = selectedPlaylist.SortedStreams[i];
                    int kbps = 0;
                    if (stream.AngleIndex > 0)
                    {
                        kbps = (int)Math.Round((double)stream.ActiveBitRate / 1000);
                    }
                    else
                    {
                        kbps = (int)Math.Round((double)stream.BitRate / 1000);
                    }
                    item.SubItems[2].Text = string.Format(
                        "{0} kbps", kbps);
                    item.SubItems[3].Text =
                        stream.Description;
                }
            }
        }

        #endregion

        #region Scan BDROM

        private BackgroundWorker ScanBDROMWorker = null;

        private class ScanBDROMState
        {
            public long TotalBytes = 0;
            public long FinishedBytes = 0;
            public DateTime TimeStarted = DateTime.Now;
            public TSStreamFile StreamFile = null;
            public Dictionary<string, List<TSPlaylistFile>> PlaylistMap =
                new Dictionary<string, List<TSPlaylistFile>>();
        }

        private void ScanBDROM()
        {
            if (ScanBDROMWorker != null &&
                ScanBDROMWorker.IsBusy)
            {
                ScanBDROMWorker.CancelAsync();
                return;
            }

            buttonScan.Text = "Cancel Scan";
            progressBarScan.Value = 0;
            progressBarScan.Minimum = 0;
            progressBarScan.Maximum = 100;
            labelProgress.Text = "Scanning disc...";
            labelTimeElapsed.Text = "00:00:00";
            labelTimeRemaining.Text = "00:00:00";
            buttonBrowse.Enabled = false;
            buttonRescan.Enabled = false;

            List<TSStreamFile> streamFiles = new List<TSStreamFile>();
            if (listViewPlaylistFiles.CheckedItems == null ||
                listViewPlaylistFiles.CheckedItems.Count == 0)
            {
                foreach (TSStreamFile streamFile
                    in BDROM.StreamFiles.Values)
                {
                    streamFiles.Add(streamFile);
                }
            }
            else
            {
                foreach (ListViewItem item
                    in listViewPlaylistFiles.CheckedItems)
                {
                    if (BDROM.PlaylistFiles.ContainsKey(item.Text))
                    {
                        TSPlaylistFile playlist =
                            BDROM.PlaylistFiles[item.Text];

                        foreach (TSStreamClip clip
                            in playlist.StreamClips)
                        {
                            if (!streamFiles.Contains(clip.StreamFile))
                            {
                                streamFiles.Add(clip.StreamFile);
                            }
                        }
                    }
                }
            }

            ScanBDROMWorker = new BackgroundWorker();
            ScanBDROMWorker.WorkerReportsProgress = true;
            ScanBDROMWorker.WorkerSupportsCancellation = true;
            ScanBDROMWorker.DoWork += ScanBDROMWork;
            ScanBDROMWorker.ProgressChanged += ScanBDROMProgress;
            ScanBDROMWorker.RunWorkerCompleted += ScanBDROMCompleted;
            ScanBDROMWorker.RunWorkerAsync(streamFiles);
        }

        private void ScanBDROMWork(
            object sender,
            DoWorkEventArgs e)
        {
            System.Threading.Timer timer = null;
            try
            {
                List<TSStreamFile> streamFiles =
                    (List<TSStreamFile>)e.Argument;

                ScanBDROMState scanState = new ScanBDROMState();
                foreach (TSStreamFile streamFile in streamFiles)
                {
                    scanState.TotalBytes += streamFile.FileInfo.Length;

                    if (!scanState.PlaylistMap.ContainsKey(streamFile.Name))
                    {
                        scanState.PlaylistMap[streamFile.Name] = new List<TSPlaylistFile>();
                    }

                    foreach (TSPlaylistFile playlist
                        in BDROM.PlaylistFiles.Values)
                    {
                        playlist.ClearBitrates();

                        foreach (TSStreamClip clip in playlist.StreamClips)
                        {
                            if (clip.Name == streamFile.Name)
                            {
                                if (!scanState.PlaylistMap[streamFile.Name].Contains(playlist))
                                {
                                    scanState.PlaylistMap[streamFile.Name].Add(playlist);
                                }
                            }
                        }
                    }
                }

                timer = new System.Threading.Timer(
                    ScanBDROMEvent, scanState, 1000, 1000);

                foreach (TSStreamFile streamFile in streamFiles)
                {
                    scanState.StreamFile = streamFile;

                    Thread thread = new Thread(ScanBDROMThread);
                    thread.Start(scanState);
                    while (thread.IsAlive)
                    {
                        if (ScanBDROMWorker.CancellationPending)
                        {
                            e.Result = new Exception("Scan was cancelled.");
                            thread.Abort();
                            return;
                        }
                        Thread.Sleep(0);
                    }
                    scanState.FinishedBytes += streamFile.FileInfo.Length;
                }
                e.Result = null;
            }
            catch (Exception ex)
            {
                e.Result = ex;
            }
            finally
            {
                if (timer != null)
                {
                    timer.Dispose();
                }
            }
        }

        private void ScanBDROMThread(
            object parameter)
        {
            try
            {
                ScanBDROMState scanState = (ScanBDROMState)parameter;
                TSStreamFile streamFile = scanState.StreamFile;
                List<TSPlaylistFile> playlists = scanState.PlaylistMap[streamFile.Name];
                streamFile.Scan(playlists, true);
            }
            catch { }
        }

        private void ScanBDROMEvent(
            object state)
        {
            try
            {
                if (ScanBDROMWorker.IsBusy &&
                    !ScanBDROMWorker.CancellationPending)
                {
                    ScanBDROMWorker.ReportProgress(0, state);
                }
            }
            catch { }
        }

        private void ScanBDROMProgress(
            object sender,
            ProgressChangedEventArgs e)
        {
            ScanBDROMState scanState = (ScanBDROMState)e.UserState;

            try
            {
                if (scanState.StreamFile != null)
                {
                    labelProgress.Text = string.Format(
                        "Scanning {0}...\r\n",
                        scanState.StreamFile.Name);
                }

                long finishedBytes = scanState.FinishedBytes;
                if (scanState.StreamFile != null)
                {
                    finishedBytes += scanState.StreamFile.Size;
                }

                double progress = ((double)finishedBytes / scanState.TotalBytes);
                int progressValue = (int)Math.Round(progress * 100);
                if (progressValue < 0) progressValue = 0;
                if (progressValue > 100) progressValue = 100;
                progressBarScan.Value = progressValue;

                TimeSpan elapsedTime = DateTime.Now.Subtract(scanState.TimeStarted);
                TimeSpan remainingTime;
                if (progress > 0 && progress < 1)
                {
                    remainingTime = new TimeSpan(
                        (long)((double)elapsedTime.Ticks / progress) - elapsedTime.Ticks);
                }
                else
                {
                    remainingTime = new TimeSpan(0);
                }

                labelTimeElapsed.Text = string.Format(
                    "{0:D2}:{1:D2}:{2:D2}",
                    elapsedTime.Hours,
                    elapsedTime.Minutes,
                    elapsedTime.Seconds);

                labelTimeRemaining.Text = string.Format(
                    "{0:D2}:{1:D2}:{2:D2}",
                    remainingTime.Hours,
                    remainingTime.Minutes,
                    remainingTime.Seconds);

                UpdatePlaylistBitrates();
            }
            catch { }
        }

        private void ScanBDROMCompleted(
            object sender,
            RunWorkerCompletedEventArgs e)
        {
            buttonScan.Enabled = false;

            UpdatePlaylistBitrates();

            labelProgress.Text = "Scan complete.";
            progressBarScan.Value = 100;
            labelTimeRemaining.Text = "00:00:00";

            if (e.Result != null)
            {
                string msg = string.Format(
                    "{0}", ((Exception)e.Result).Message);

                MessageBox.Show(msg, "BDInfo Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            else
            {
                if (BDMuxSettings.AutosaveReport)
                {
                    GenerateReport();
                }
                else
                {
                    MessageBox.Show(
                        "Scan completed successfully.", "BDInfo Scan",
                        MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
            buttonBrowse.Enabled = true;
            buttonRescan.Enabled = true;
            buttonScan.Enabled = true;
            buttonScan.Text = "Scan Bitrates";
        }

        #endregion

        #region Report Generation

        private BackgroundWorker ReportWorker = null;

        private void GenerateReport()
        {
            ShowNotification("Please wait while we generate the report...");
            buttonViewReport.Enabled = false;

            List<TSPlaylistFile> playlists = new List<TSPlaylistFile>();
            if (listViewPlaylistFiles.CheckedItems == null ||
                listViewPlaylistFiles.CheckedItems.Count == 0)
            {
                foreach (ListViewItem item
                    in listViewPlaylistFiles.Items)
                {
                    if (BDROM.PlaylistFiles.ContainsKey(item.Text))
                    {
                        playlists.Add(BDROM.PlaylistFiles[item.Text]);
                    }
                }
            }
            else
            {
                foreach (ListViewItem item
                    in listViewPlaylistFiles.CheckedItems)
                {
                    if (BDROM.PlaylistFiles.ContainsKey(item.Text))
                    {
                        playlists.Add(BDROM.PlaylistFiles[item.Text]);
                    }
                }
            }

            ReportWorker = new BackgroundWorker();
            ReportWorker.WorkerReportsProgress = true;
            ReportWorker.WorkerSupportsCancellation = true;
            ReportWorker.DoWork += GenerateReportWork;
            ReportWorker.ProgressChanged += GenerateReportProgress;
            ReportWorker.RunWorkerCompleted += GenerateReportCompleted;
            ReportWorker.RunWorkerAsync(playlists);
        }

        private void GenerateReportWork(
            object sender,
            DoWorkEventArgs e)
        {
            try
            {
                List<TSPlaylistFile> playlists = (List<TSPlaylistFile>)e.Argument;
                FormReport report = new FormReport();
                report.Generate(BDROM, playlists);
                e.Result = report;
            }
            catch (Exception ex)
            {
                e.Result = ex;
            }
        }

        private void GenerateReportProgress(
            object sender,
            ProgressChangedEventArgs e)
        {
        }

        private void GenerateReportCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            HideNotification();
            if (e.Result != null)
            {
                if (e.Result.GetType().Name == "FormReport")
                {
                    ((Form)e.Result).Show();
                }
                else if (e.Result.GetType().Name == "Exception")
                {
                    string msg = string.Format(
                        "{0}", ((Exception)e.Result).Message);

                    MessageBox.Show(msg, "BDInfo Error",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            buttonViewReport.Enabled = true;
        }

        #endregion

        #region Notification Display

        private Form FormNotification = null;

        private void ShowNotification(
            string text)
        {
            HideNotification();

            Label label = new Label();
            label.AutoSize = true;
            label.Font = new Font(Font.SystemFontName, 12);
            label.Text = text;

            FormNotification = new Form();
            FormNotification.ControlBox = false;
            FormNotification.ShowInTaskbar = false;
            FormNotification.ShowIcon = false;
            FormNotification.FormBorderStyle = FormBorderStyle.Fixed3D;
            FormNotification.Controls.Add(label);
            FormNotification.Size = new Size(label.Width + 10, 18);
            FormNotification.Show(this);
            FormNotification.Location = new Point(
                this.Location.X + this.Width / 2 - FormNotification.Width / 2,
                this.Location.Y + this.Height / 2 - FormNotification.Height / 2);
        }

        private void HideNotification()
        {
            if (FormNotification != null &&
                !FormNotification.IsDisposed)
            {
                FormNotification.Close();
                FormNotification = null;
            }
        }

        private void UpdateNotification()
        {
            if (FormNotification != null &&
                !FormNotification.IsDisposed &&
                FormNotification.Visible)
            {
                FormNotification.Location = new Point(
                    this.Location.X + this.Width / 2 - FormNotification.Width / 2,
                    this.Location.Y + this.Height / 2 - FormNotification.Height / 2);
            }
        }

        private void FormMain_Resize(object sender, EventArgs e)
        {
            ResetColumnWidths();
            UpdateNotification();
        }

        private void FormMain_LocationChanged(object sender, EventArgs e)
        {
            UpdateNotification();
        }

        #endregion

        public static int ComparePlaylistFiles(
            TSPlaylistFile x,
            TSPlaylistFile y)
        {
            if (x == null && y == null)
            {
                return 0;
            }
            else if (x == null && y != null)
            {
                return 1;
            }
            else if (x != null && y == null)
            {
                return -1;
            }
            else
            {
                if (x.TotalLength > y.TotalLength)
                {
                    return -1;
                }
                else if (y.TotalLength > x.TotalLength)
                {
                    return 1;
                }
                else
                {
                    return x.Name.CompareTo(y.Name);
                }
            }
        }

        private void buttonMux_Click(object sender, EventArgs e)
        {

            string destDir = "";

            if (!textBoxTarget.Text.EndsWith("\\"))
                textBoxTarget.Text += "\\";

            destDir = textBoxTarget.Text + seriesName + "\\";
            try
            {
                Directory.CreateDirectory(destDir);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                DialogResult result = MessageBox.Show(string.Format(
                "An error occurred while creating the target directory {0}.\n\nYou may not have enough permissions or the name may be invalid.", destDir),
                "BDMux Create Directory Error", MessageBoxButtons.OK);
                return;
            }

            string tempDir = "";

            if (!textBoxTemp.Text.EndsWith("\\"))
                textBoxTemp.Text += "\\";

            tempDir = textBoxTemp.Text + seriesName + "\\";
            try
            {
                Directory.CreateDirectory(tempDir);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                DialogResult result = MessageBox.Show(string.Format(
                "An error occurred while creating the temporary directory {0}.\n\nYou may not have enough permissions or the name may be invalid.", tempDir),
                "BDMux Create Directory Error", MessageBoxButtons.OK);
                return;
            }            

            Dictionary<string, string> playlistNumbers = new Dictionary<string, string>();
            Dictionary<string, string> items = new Dictionary<string, string>();
            if (listViewPlaylistFiles.CheckedItems == null ||
                listViewPlaylistFiles.CheckedItems.Count == 0)
            {

                foreach (ListViewItem item in listViewPlaylistFiles.Items)
                    items[item.Text] = item.SubItems[5].Text;
            }
            else 
            {
                foreach (ListViewItem item in listViewPlaylistFiles.CheckedItems)
                    items[item.Text] = item.SubItems[5].Text;
            }
            foreach (string iPlay in items.Keys)                    
            {
                if (BDROM.PlaylistFiles.ContainsKey(iPlay))
                {
                    myMuxer = new Muxer(BDROM.DirectoryBDMV.FullName, destDir);
                    myMuxer.tempDir = tempDir;
                    myMuxer.muxPlaylist.name = BDROM.PlaylistFiles[iPlay].Name;
                    myMuxer.muxPlaylist.videoCodec = BDROM.PlaylistFiles[iPlay].VideoStreams[0].CodecShortName;
                    myMuxer.muxPlaylist.framesNumerator = BDROM.PlaylistFiles[iPlay].VideoStreams[0].FrameRateEnumerator;
                    myMuxer.muxPlaylist.framesDenominator = BDROM.PlaylistFiles[iPlay].VideoStreams[0].FrameRateDenominator;
                    myMuxer.muxPlaylist.finalName = items[iPlay];
                    
                    int i = 2;
                    Dictionary<string, TSStreamClip> reportedClips = new Dictionary<string, TSStreamClip>();
                    //TSStreamClip clip = BDROM.PlaylistFiles[iPlay].StreamClips[0];
                    List <TSStream> clip = BDROM.PlaylistFiles[iPlay].SortedStreams;
                    
                   // if (clip.StreamFile != null)
                    if (clip != null)
                    {
                        //foreach (TSStream clipStream in clip.StreamFile.Streams.Values) 
                        foreach (TSStream clipStream in clip)
                        {
                            if (clipStream.process)
                            {
                                MXStreams str = new MXStreams();
                                str.codec = clipStream.CodecShortName.Substring(0, 3);
                                
                                if (clipStream.CodecShortName == "DTSHD")
                                    str.DTSHD = true;
                                
                                TSStream playlistStream = BDROM.PlaylistFiles[iPlay].Streams[clipStream.PID];
                                str.language = "";
                                if (playlistStream.LanguageCode != null &&
                                       playlistStream.LanguageCode.Length > 0)
                                {
                                    str.language = string.Format(
                                        "{0}", playlistStream.LanguageCode);
                                }
                                
                                str.number = i.ToString();
                                str.PID = clipStream.PID.ToString();
                                myMuxer.muxPlaylist.muxStreams.Add(str);
                            }
                            i++;
                        }
                    }
                    //  }

                    lastQueueItem++;
                    ListViewItem item = listViewQueue.Items.Add(lastQueueItem.ToString());
                    item.Checked = true;
                    item.SubItems.Add("Demux");
                    item.SubItems.Add("Ready");
                    myMuxer.jobType = 1; //DeMux
                    myMuxer.dependsOn = 0;
                    myMuxer.dDTS = BDMuxSettings.DecodeDTS;
                    myMuxer.jobId = lastQueueItem;
                    myMuxer.jobStatus = 1; //Ready
                    muxQueue.Add((Muxer)myMuxer.Clone());
                    int demuxJob = lastQueueItem;
                    int encodeJob = demuxJob;

                    if (comboBoxX264conv.SelectedIndex != 0)
                    {
                        lastQueueItem++;
                        item = listViewQueue.Items.Add(lastQueueItem.ToString());
                        item.Checked = true;
                        item.SubItems.Add("x264 Encoding");
                        item.SubItems.Add("Waiting on " + demuxJob.ToString());
                        myMuxer.jobType = 6; //x264 Encoding
                        myMuxer.dependsOn = demuxJob;
                        myMuxer.jobId = lastQueueItem;
                        encodeJob = lastQueueItem;
                        myMuxer.jobStatus = 2; //Pending
                        myMuxer.muxPlaylist.encode = true;
                        myMuxer.crf = comboBoxX264conv.SelectedIndex;
                        muxQueue.Add((Muxer)myMuxer.Clone());
                    }

                    lastQueueItem++;
                    item = listViewQueue.Items.Add(lastQueueItem.ToString());
                    item.Checked = true;
                    item.SubItems.Add("Subtitle conversion");
                    item.SubItems.Add("Waiting on " + encodeJob.ToString());
                    myMuxer.jobType = 2; //Subtitle conversion
                    myMuxer.dependsOn = encodeJob;
                    myMuxer.jobId = lastQueueItem;
                    myMuxer.jobStatus = 2; //Pending
                    muxQueue.Add((Muxer)myMuxer.Clone());
                    
                    lastQueueItem++;
                    item = listViewQueue.Items.Add(lastQueueItem.ToString());
                    item.Checked = true;
                    item.SubItems.Add("Mux");
                    item.SubItems.Add("Waiting on " + (lastQueueItem - 1).ToString());
                    myMuxer.jobType = 3; //Mux
                    myMuxer.dependsOn = lastQueueItem - 1;
                    myMuxer.jobId = lastQueueItem;
                    myMuxer.jobStatus = 2; //Pending
                    int muxJob = lastQueueItem;
                    muxQueue.Add((Muxer)myMuxer.Clone());

                    if (checkBoxRemove.Checked)
                    {
                        lastQueueItem++;
                        item = listViewQueue.Items.Add(lastQueueItem.ToString());
                        item.Checked = true;
                        item.SubItems.Add("Remove Temp Files");
                        item.SubItems.Add("Waiting on " + muxJob.ToString());
                        myMuxer.jobType = 4; //Remove Temporary Files
                        myMuxer.dependsOn = muxJob;
                        myMuxer.jobId = lastQueueItem;
                        myMuxer.jobStatus = 2; //Pending
                        muxQueue.Add((Muxer)myMuxer.Clone());
                    }

                    //FTP Transfer
                    if (checkBoxFTP.Checked)
                    {

                        myMuxer.ftpDir = ftpDir;
                        myMuxer.ftpPWD = ftpPWD;
                        myMuxer.ftpServer = ftpServer;
                        myMuxer.ftpUserName = ftpUserName;

                        lastQueueItem++;
                        item = listViewQueue.Items.Add(lastQueueItem.ToString());
                        item.Checked = true;
                        item.SubItems.Add("FTP");
                        item.SubItems.Add("Waiting on " + muxJob.ToString());
                        myMuxer.jobType = 5; //FTP files
                        myMuxer.dependsOn = muxJob;
                        myMuxer.jobId = lastQueueItem;
                        myMuxer.jobStatus = 2; //Pending
                        muxQueue.Add((Muxer)myMuxer.Clone());
                    }
                }
            }
            
        }

        private void buttonBrowseTarget_Click(object sender, EventArgs e)
        {
            string path = null;
            try
            {
                FolderBrowserDialog dialog = new FolderBrowserDialog();
                dialog.Description = "Select a Target Folder:";
                dialog.ShowNewFolderButton = false;
                if (dialog.ShowDialog() == DialogResult.OK)
                {
                    path = dialog.SelectedPath;
                    
                    textBoxTarget.Text = path;
                }
            }
            catch (Exception ex)
            {
                string msg = string.Format(
                    "Error opening path {0}: {1}{2}",
                    path,
                    ex.Message,
                    Environment.NewLine);

                MessageBox.Show(msg, "BD2MKV Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void buttonBrowseTemp_Click(object sender, EventArgs e)
        {
            string path = null;
            try
            {
                FolderBrowserDialog dialog = new FolderBrowserDialog();
                dialog.Description = "Select a Folder for Temp files:";
                dialog.ShowNewFolderButton = false;
                if (dialog.ShowDialog() == DialogResult.OK)
                {
                    path = dialog.SelectedPath;

                    textBoxTemp.Text = path;
                }
            }
            catch (Exception ex)
            {
                string msg = string.Format(
                    "Error opening path {0}: {1}{2}",
                    path,
                    ex.Message,
                    Environment.NewLine);

                MessageBox.Show(msg, "BD2MKV Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void LoadSeries()
        {
            if (listViewPlaylistFiles.Items.Count == 0)
                return;

            if (radioButtonTV.Checked)
            {
                List<Episode> series = null;

                if (seriesId != null)
                {
                    series = TheTVDB.series.FindAll(delegate(Episode ep) { return ep.seriesId == seriesId; });
                }
                else
                {
                    series = new List<Episode>();
                }

                buttonMux.Enabled = true;
                decimal seasonNumber = numericUpDownSeason.Value;
                decimal epNumber = numericUpDownEpisode.Value;

                foreach (ListViewItem item in listViewPlaylistFiles.Items)
                {
                    Episode ep1 = series.Find(delegate(Episode ep)
                    {
                        return (ep.seasonNumber == seasonNumber.ToString()
                        && ep.episodeNumber == epNumber.ToString());
                    });

                    string tmpName = "-";
                    if (ep1 != null)
                        tmpName = ep1.episodeName;

                    string tmpEpNumber = "";

                    switch (comboBoxScheme.Text)
                    {
                        case "S01E01":
                            tmpEpNumber = "S" + string.Format("{0:00}", seasonNumber) + "E" + string.Format("{0:00}", epNumber);
                            break;
                        case "1x01":
                            tmpEpNumber = seasonNumber.ToString() + "x" + string.Format("{0:00}", epNumber);
                            break;
                        case "01-01":
                            tmpEpNumber = string.Format("{0:00}", seasonNumber) + "-" + string.Format("{0:00}", epNumber);
                            break;
                        case "101":
                            tmpEpNumber = seasonNumber.ToString() + string.Format("{0:00}", epNumber);
                            break;
                    }
                    tmpName = seriesName + " " + tmpEpNumber + " " + tmpName + ".mkv";
                    item.SubItems[5].Text = tmpName;
                    epNumber++;
                }
            }
            else
            {
                buttonMux.Enabled = true;
                foreach (ListViewItem item in listViewPlaylistFiles.Items)
                {
                    item.SubItems[5].Text = seriesName + ".mkv";
                }
            }
            listViewPlaylistFiles.Refresh();
        }

        private void ExtractOnOutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (e.Data != null)
            {
                               
                
                
                char[] delimiters = new char[] { ':', ',' };
                char[] leaders = new char[] { '-','\b',' '};
                
                String tmpDescription = e.Data.TrimStart(leaders);
                String[] token = tmpDescription.Split(delimiters);
                
                string tmpTrack = token[0];
                if (token.Length < 2)
                {
                    Console.WriteLine("Message:");
                    Console.WriteLine(tmpDescription);
                    return;
                }
                if (token[0] == "MKV")
                {
                    string tmpDuration = token[4].Trim() + ":" + token[5] + ":" + token[6].Trim();
                    Console.WriteLine("Message:");
                    Console.WriteLine(tmpDescription);                  
                    return;
                }
                string tmpCodec = token[1].Trim();
                string tmpLanguage = "";
                string tmpBitrate = "";

                if (tmpCodec.StartsWith("Subtitle")) tmpCodec = "PGS";
                
                switch (tmpCodec.Substring(0, 3))
                {
                    case "AC3":
                    case "DTS":
                        tmpLanguage = token[2].Trim();
                        if (!tmpCodec.StartsWith("DTS-HD"))
                            tmpBitrate = token[3].Trim();
                        break;
                    case "RAW":
                    case "Tru":
                    case "PGS":
                        tmpLanguage = token[2].Trim();
                        break;
                }
                Console.WriteLine("Message:");
                Console.WriteLine(tmpDescription);    
            }
        }

        private void ExtractOnErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (e.Data != null)
            {
                Console.WriteLine("Error:");
                Console.WriteLine(e.Data);
            }          
        }


        private void ExtractOnProcessExited(object sender, EventArgs e)
        {
            Console.WriteLine("Finished.");
        }

        private void InitFile(string file)
        {
            if (!BDMuxSettings.eac3toLocation.EndsWith("\\"))
                BDMuxSettings.eac3toLocation += "\\";

            System.Diagnostics.Process proc = new System.Diagnostics.Process();
            proc.StartInfo.UseShellExecute = false;
            proc.EnableRaisingEvents = true;
            proc.StartInfo.CreateNoWindow = true;
            proc.StartInfo.RedirectStandardOutput = true;
            proc.StartInfo.RedirectStandardError = true;
            proc.OutputDataReceived += new DataReceivedEventHandler(ExtractOnOutputDataReceived);
            proc.ErrorDataReceived += new DataReceivedEventHandler(ExtractOnErrorDataReceived);
            proc.Exited += new EventHandler(ExtractOnProcessExited);
            proc.StartInfo.FileName = "\"" + BDMuxSettings.eac3toLocation + "eac3to.exe\"";
            proc.StartInfo.Arguments = "\"" + file + "\"";
            proc.Start();
            proc.BeginOutputReadLine();
            proc.WaitForExit();
        }

        private void buttonShow_Click(object sender, EventArgs e)
        {
            FormShow show = new FormShow();

            show.label = textBoxSeries.Text;
            if (show.ShowDialog() == DialogResult.OK)
            {
                seriesId = show.seriesId;
                seriesName = RemoveInvalidFileNameChars(show.seriesName);
                textBoxSeries.Text = seriesName;
                language = show.language;
                ShowNotification("Please wait while we load the episode names...");

                buttonBrowse.Enabled = false;
                buttonRescan.Enabled = false;
                buttonShow.Enabled = false;
                buttonSelectAll.Enabled = false;
                buttonUnselectAll.Enabled = false;
                buttonCustomPlaylist.Enabled = false;
                buttonScan.Enabled = false;
                buttonMux.Enabled = false;
                buttonViewReport.Enabled = false;
                textBoxDetails.Enabled = false;
                listViewPlaylistFiles.Enabled = false;
                listViewStreamFiles.Enabled = false;
                listViewStreams.Enabled = false;

                BackgroundWorker LoadNamesWorker = new BackgroundWorker();
                LoadNamesWorker.WorkerReportsProgress = true;
                LoadNamesWorker.WorkerSupportsCancellation = true;
                LoadNamesWorker.DoWork += LoadNamesWork;
                LoadNamesWorker.RunWorkerCompleted += LoadNamesCompleted;
                LoadNamesWorker.RunWorkerAsync();
            }

        }

        private void LoadNamesWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                TheTVDB.LoadSeries(seriesId, language);               
            }
            catch (Exception ex)
            {
                e.Result = ex;
            }
        }

        private void LoadNamesCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            HideNotification();
            buttonBrowse.Enabled = true;
            buttonRescan.Enabled = true;
            buttonScan.Enabled = true;
            buttonShow.Enabled = true;
            buttonMux.Enabled = true;
            buttonSelectAll.Enabled = true;
            buttonUnselectAll.Enabled = true;
            buttonCustomPlaylist.Enabled = true;
            buttonViewReport.Enabled = true;
            textBoxDetails.Enabled = true;
            listViewPlaylistFiles.Enabled = true;
            listViewStreamFiles.Enabled = true;
            listViewStreams.Enabled = true;
            LoadSeries();
        }

        private void comboBoxScheme_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (comboBoxScheme.SelectedItem != null) 
                LoadSeries();
        }

        private void numericUpDownEpisode_ValueChanged(object sender, EventArgs e)
        {
            LoadSeries();
        }

        private void numericUpDownSeason_ValueChanged(object sender, EventArgs e)
        {
            LoadSeries();
        }


        private void buttonRemove_Click(object sender, EventArgs e)
        {
            if (listViewPlaylistFiles.SelectedItems != null)
            {
                foreach (ListViewItem item in listViewPlaylistFiles.SelectedItems)
                    listViewPlaylistFiles.Items.RemoveAt(item.Index);
                buttonRemove.Enabled = false;
                LoadSeries();
            }
        }

        private void buttonRename_Click(object sender, EventArgs e)
        {
            listViewPlaylistFiles.SelectedItems[0].SubItems[5].Text = textBoxRename.Text;
            
        }

        private void buttonFTP_Click(object sender, EventArgs e)
        {
            FormFTP ftpForm = new FormFTP();

            if (ftpForm.ShowDialog() == DialogResult.OK)
            {
                ftpDir = ftpForm.ftpDir;
                ftpPWD = ftpForm.ftpPWD;
                ftpServer = ftpForm.ftpServer;
                ftpUserName = ftpForm.ftpUserName;
            }
        }

        private void checkBoxFTP_CheckedChanged(object sender, EventArgs e)
        {
            buttonFTP.Enabled = checkBoxFTP.Checked;
        }

        private void textBoxSeries_TextChanged(object sender, EventArgs e)
        {
            textBoxSeries.Text = RemoveInvalidFileNameChars(textBoxSeries.Text);
            seriesName = textBoxSeries.Text;
            LoadSeries();
            if (listViewPlaylistFiles.SelectedItems.Count > 0)
                textBoxRename.Text = listViewPlaylistFiles.SelectedItems[0].SubItems[5].Text;
            
        }

        private void buttonMovie_Click(object sender, EventArgs e)
        {
            FormMovie movie = new FormMovie();

            movie.label = textBoxMovie.Text;
            if (movie.ShowDialog() == DialogResult.OK)
            {
                seriesId = movie.movieId;
                seriesName = RemoveInvalidFileNameChars(movie.movieName);
                textBoxMovie.Text = seriesName;
                language = movie.language;
                ShowNotification("Please wait while we load the movie names...");

                buttonBrowse.Enabled = false;
                buttonRescan.Enabled = false;
                buttonShow.Enabled = false;
                buttonSelectAll.Enabled = false;
                buttonUnselectAll.Enabled = false;
                buttonCustomPlaylist.Enabled = false;
                buttonScan.Enabled = false;
                buttonMux.Enabled = false;
                buttonViewReport.Enabled = false;
                textBoxDetails.Enabled = false;
                listViewPlaylistFiles.Enabled = false;
                listViewStreamFiles.Enabled = false;
                listViewStreams.Enabled = false;

                LoadSeries();
                HideNotification();
                buttonBrowse.Enabled = true;
                buttonRescan.Enabled = true;
                buttonScan.Enabled = true;
                buttonShow.Enabled = true;
                buttonMux.Enabled = true;
                buttonSelectAll.Enabled = true;
                buttonUnselectAll.Enabled = true;
                buttonCustomPlaylist.Enabled = true;
                buttonViewReport.Enabled = true;
                textBoxDetails.Enabled = true;
                listViewPlaylistFiles.Enabled = true;
                listViewStreamFiles.Enabled = true;
                listViewStreams.Enabled = true;
            }
        }

        private void radioButtonTV_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonTV.Checked)
                groupBoxTV.Enabled = true;
            else
                groupBoxTV.Enabled = false;
        }

        private void radioButtonMovie_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonMovie.Checked)
                groupBoxMovie.Enabled = true;
            else
                groupBoxMovie.Enabled = false;
        }

        private void textBoxMovie_TextChanged(object sender, EventArgs e)
        {
            textBoxMovie.Text = RemoveInvalidFileNameChars(textBoxMovie.Text);
            seriesName = textBoxMovie.Text;
            LoadSeries();
            if (listViewPlaylistFiles.SelectedItems.Count > 0)
                textBoxRename.Text = listViewPlaylistFiles.SelectedItems[0].SubItems[5].Text;
        }

        
        private void checkBox3_CheckedChanged(object sender, EventArgs e)
        {
            combos[2] = checkBoxThread3.Checked;
        }

        private void checkBoxThread1_CheckedChanged(object sender, EventArgs e)
        {
            combos[0] = checkBoxThread1.Checked;
        }

        private void checkBoxThread2_CheckedChanged(object sender, EventArgs e)
        {
            combos[1] = checkBoxThread2.Checked;
        }

        private void checkBoxThread4_CheckedChanged(object sender, EventArgs e)
        {
            combos[3] = checkBoxThread4.Checked;
        }

        private void listViewQueue_ItemCheck(object sender, ItemCheckEventArgs e)
        {
            string lbl = listViewQueue.Items[e.Index].SubItems[2].Text;
               
            if ((lbl == "In Progress...") || (lbl == "Finished"))
            {
                e.NewValue = e.CurrentValue;
                return;
            }
          
            int job = Convert.ToInt32(listViewQueue.Items[e.Index].Text);
            Muxer m = muxQueue.Find(delegate(Muxer mx) { return mx.jobId == job; });
            
            if (m == null)
            {
                e.NewValue = e.CurrentValue;
                return;
            }

            if (e.NewValue == CheckState.Unchecked)
            {
                m.jobStatus += 10;
                listViewQueue.Items[e.Index].SubItems[2].Text += " (On hold)";
            }
            else
            {
                if (m.jobStatus > 10)
                {
                    m.jobStatus -= 10;
                    listViewQueue.Items[e.Index].SubItems[2].Text = lbl.Replace(" (On hold)", "");
                }
            }

        }

        private void buttonRemoveTask_Click(object sender, EventArgs e)
        {
            if (listViewQueue.SelectedItems.Count == 0)
                return;

            ListViewItem item = listViewQueue.SelectedItems[0];
            int job = Convert.ToInt32(item.Text);
            string lbl = item.SubItems[2].Text;

            if ((lbl == "In Progress..."))
            {
                return;
            }

            if ((lbl == "Finished"))
            {
                listViewQueue.Items.Remove(item);
                Muxer m = muxQueue.Find(delegate(Muxer mx) { return mx.jobId == job; });
                if (m != null)
                    muxQueue.Remove(m);
                return;
            }

            Stack<int> deps = new Stack<int>();
            deps.Push(job);

            lock (padlock)
            {
                if (listViewQueue.Items[item.Index].SubItems[2].Text == "In Progress...")
                    return;

                if (listViewQueue.Items[item.Index].SubItems[2].Text == "Finished")
                    return;

                while (deps.Count > 0)
                {
                    job = deps.Pop();
                    Muxer m = null;    
               
                    foreach (Muxer mux in muxQueue)
                    {
                        if (mux.dependsOn == job)
                            deps.Push(mux.jobId);

                        if (mux.jobId == job)
                            m = mux;

                    }
                    if (m!=null)
                        muxQueue.Remove(m);
                    listViewQueue.Items.RemoveByKey(job.ToString());                    
                }
            }
        }

        private void listViewQueue_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listViewQueue.SelectedItems.Count > 0)
                buttonRemoveTask.Enabled = true;
            else
                buttonRemoveTask.Enabled = false;
        }

        private void buttonClearTask_Click(object sender, EventArgs e)
        {
            foreach (Muxer m in muxQueue)
                if (m.jobStatus == 4)
                    muxQueue.Remove(m);

            foreach (ListViewItem item in listViewQueue.Items)
                if (item.SubItems[2].Text == "Finished")
                    listViewQueue.Items.Remove(item);
        }

        private void listViewStreams_ItemCheck(object sender, ItemCheckEventArgs e)
        {
            ListViewItem playlistItem = listViewPlaylistFiles.SelectedItems[0];                        

            TSPlaylistFile playlist = null;
            playlist = BDROM.PlaylistFiles[playlistItem.Text];
            playlist.SortedStreams[e.Index].process = (e.NewValue == CheckState.Checked);
        }

        private void comboBoxSource_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (comboBoxSource.SelectedIndex == 0)
            {
                BDMuxSettings.LastFilePath = textBoxSource.Text;
                textBoxSource.Text = BDMuxSettings.LastPath;
            }
            else
            {
                BDMuxSettings.LastPath = textBoxSource.Text;
                textBoxSource.Text = BDMuxSettings.LastFilePath;
            }
        }

        private void comboBoxX264conv_SelectedIndexChanged(object sender, EventArgs e)
        {

        }
    }

    public class ListViewColumnSorter : IComparer
    {
        private int ColumnToSort;
        private SortOrder OrderOfSort;
        private CaseInsensitiveComparer ObjectCompare;

        public ListViewColumnSorter()
        {
            ColumnToSort = 0;
            OrderOfSort = SortOrder.None;
            ObjectCompare = new CaseInsensitiveComparer();
        }

        public int Compare(
            object x, 
            object y)
        {
            ListViewItem listviewX = (ListViewItem)x;
            ListViewItem listviewY = (ListViewItem)y;
            
            int compareResult = ObjectCompare.Compare(
                listviewX.SubItems[ColumnToSort].Tag, 
                listviewY.SubItems[ColumnToSort].Tag);
            
            if (OrderOfSort == SortOrder.Ascending)
            {
                return compareResult;
            }
            else if (OrderOfSort == SortOrder.Descending)
            {
                return (-compareResult);
            }
            else
            {
                return 0;
            }
        }

        public int SortColumn
        {
            set
            {
                ColumnToSort = value;
            }
            get
            {
                return ColumnToSort;
            }
        }

        public SortOrder Order
        {
            set
            {
                OrderOfSort = value;
            }
            get
            {
                return OrderOfSort;
            }
        }
    }

}
